package com.telnetnz.ticketdesk.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import net.sf.ehcache.Element;

import org.apache.log4j.Logger;

import com.rockbb.common.sso.acl.ACLBuilder;
import com.rockbb.common.sso.session.BasicUserFactory;
import com.rockbb.common.sso.session.Session;
import com.rockbb.common.sso.session.SessionConstants;
import com.rockbb.common.sso.session.SessionUser;
import com.rockbb.common.utilities.security.StringDigest;
import com.telnetnz.ticketdesk.bean.ProjectToUser;
import com.telnetnz.ticketdesk.bean.User;
import com.telnetnz.ticketdesk.common.config.SpringContext;
import com.telnetnz.ticketdesk.dao.entity.UserEntity;
import com.telnetnz.ticketdesk.dao.wrapper.UserWrap;

/**
 * @author Administrator
 *
 */
public class UserService
{
	private static Logger logger = Logger.getLogger(UserService.class);

	public static final int USER_LANG_ANONYMOUS = 0;
	public static final int USER_STYLE_ANONYMOUS = 0;

	public static final float USER_TZONE_ANONYMOUS = 8.0F;

	public static final float[] USER_TIMEZONE_KEYS = { -12F, -11F, -10F, -9.5F,
			-9F, -8F, -7F, -6F, -5F, -4.5F, -4F, -3.5F, -3F, -2F, -1F, 0F, 1F,
			2F, 3F, 3.5F, 4F, 4.5F, 5F, 5.5F, 5.75F, 6F, 6.5F, 7F, 8F, 8.75F,
			9F, 9.5F, 10F, 10.5F, 11F, 11.5F, 12F, 12.75F, 13F, 14F };


	public static final String USER_PERMISSION_ANONYMOUS = ACLBuilder.compress("0");

	public static final String[] STATUSES = UserWrap.STATUSES;
	public static final int USER_STATUS_NORMAL = 0;
	public static final int USER_STATUS_INACTIVATED = 1;

	public static final String[] ORDER_BY = UserWrap.ORDER_BY;
	public static final int ORDER_BY_NAME = 0;
	public static final int ORDER_BY_EMAIL = 1;
	public static final int ORDER_BY_CREATETIME = 2;

	public static final String[] ORDER = UserWrap.ORDER;

	private static String CACHE_KEY = "uid_";

	public static List<UserEntity> getEntitiesByProject(int projectId, long excludedUserId)
	{
		List<UserEntity> users = new ArrayList<UserEntity>();
		List<ProjectToUser> projectToUsers = ProjectToUserService.getByProjectId(projectId);
		for (ProjectToUser projectToUser : projectToUsers)
		{
			UserEntity entity = getWrap().select(projectToUser.getUserId());
			if (entity != null && projectToUser.getUserId() != excludedUserId)
				users.add(entity);
		}
		return users;
	}

	public static List<User> getByProject(int projectId, long excludedUserId)
	{
		List<User> users = new ArrayList<User>();
		List<ProjectToUser> projectToUsers = ProjectToUserService.getByProjectId(projectId);
		for (ProjectToUser projectToUser : projectToUsers)
		{
			if (projectToUser.getUser() != null && projectToUser.getUserId() != excludedUserId)
				users.add(projectToUser.getUser());
		}
		return users;
	}

	public static List<User> getByPageAndCondition(
			int start,
			int limit, 
			int orderby, 
			int order, 
			long excludedId,
			String name,
			String email)
	{
		List<Long> excludedIds = new ArrayList<Long>();
		if (excludedId > 0L) excludedIds.add(excludedId);
		List<Long> uids = getWrap().selectByPageAndCondition(
				start, limit, orderby, order, excludedIds, name, email);
		return adaptIdsList(uids);
	}

	public static List<User> getByPageAndCondition(
			int start,
			int limit, 
			int orderby, 
			int order, 
			List<Long> excludedIds,
			String name,
			String email)
	{
		List<Long> uids = getWrap().selectByPageAndCondition(
				start, limit, orderby, order, excludedIds, name, email);
		return adaptIdsList(uids);
	}

	public static long countByCondition(
			long excludedId,
			String name,
			String email)
	{
		List<Long> excludedIds = new ArrayList<Long>();
		if (excludedId > 0L) excludedIds.add(excludedId);
		return getWrap().countByCondition(excludedIds, name, email);
	}

	public static long countByCondition(
			List<Long> excludedIds,
			String name,
			String email)
	{
		return getWrap().countByCondition(excludedIds, name, email);
	}

	public static long countAll()
	{
		return getWrap().countAll();
	}

	/**
	 * Get one user without cache
	 * 
	 * @param id
	 * @return
	 */
	public static User getRawUser(long id)
	{
		UserEntity entity = getWrap().select(id);
		return User.adapt(entity);
	}

	/**
	 * Get user from cache
	 * 
	 * @param id
	 * @return
	 */
	public static User getUser(long id)
	{
		Element elm = getWrap().getCache().get(CACHE_KEY + id);
		User bean;
		if (elm == null)
		{
			bean = getRawUser(id);
			getWrap().getCache().put(new Element(CACHE_KEY + id, bean));
		}
		else
		{
			bean = (User) elm.getValue();
		}
		return bean;
	}

	public static User getByName(String name)
	{
		long uid = getWrap().selectByName(name);
		return getUser(uid);
	}

	public static User getByEmail(String email)
	{
		long uid = getWrap().selectByEmail(email);
		return getUser(uid);
	}

	public static void addUser(User user)
	{
		if (user == null)
			return;
		getWrap().insert(user.toEntity());
		getWrap().getCache().remove(CACHE_KEY + user.getId());
	}

	public static void updateUser(User user)
	{
		if (user == null)
			return;
		getWrap().update(user.toEntity());
		getWrap().getCache().remove(CACHE_KEY + user.getId());
	}

	public static void deleteUer(User user)
	{
		if (user == null)
			return;
		getWrap().delete(user.toEntity());
		getWrap().getCache().remove(CACHE_KEY + user.getId());
	}

	public static User adapt(SessionUser sessionUser)
	{
		if (sessionUser == null)
			return null;

		User user = new User();
		user.initialize();
		user.setName(sessionUser.getName());
		user.setEmail(sessionUser.getEmail());
		user.setLanguage(sessionUser.getLanguage());
		user.setTimezone(sessionUser.getTimezone());
		user.setStyle(sessionUser.getStyle());
		user.setCreateTime(new Date());
		user.setStatus(sessionUser.getStatus());

		user.setPermissions(sessionUser.getPermissions());

		return user;
	}

	public static User getAnonymousUser()
	{
		User user = new User();
		user.initialize();
		user.setId(SessionConstants.USER_ID_ANONYMOUS);
		user.setTimezone(USER_TZONE_ANONYMOUS);
		user.setStyle(USER_STYLE_ANONYMOUS);
		user.setStatus(USER_STATUS_NORMAL);
		user.setPermissions(USER_PERMISSION_ANONYMOUS);
		return user;
	}

	/**
	 * Verify the input user name and password. It returns true only when the user name 
	 * and password matches
	 * 
	 * @param name
	 * @param password
	 * @return
	 */
	public static boolean checkAuthorization(String name, String password) 
	{
		if (name == null || name.length() == 0 || password == null || password.length() == 0) 
		{
			return false;
		}

		User user = getByName(name);
		if (user == null) 
		{
			return false;
		}

		String cmp_hash = user.getPassword();
		String password_hash = StringDigest.hash_crypt_private(password, cmp_hash);
		if (password_hash.equals(cmp_hash))
			return true;
		else
			return false;
	}

	public static List<User> adaptIdsList(List<Long> ids)
	{
		List<User> users = new ArrayList<User>();
		if (ids != null && ids.size() > 0)
		{
			for (int i = 0; i < ids.size(); i++)
			{
				User user = getUser(ids.get(i));
				if (user == null)
					continue;
				users.add(user);
			}
		}
		return users;
	}

	private static UserWrap getWrap()
	{
		return SpringContext.getUserWrap();
	}

	public static void main(String[] args)
	{
		long total = UserService.countAll();
		int step = 200;
		for (int i=0; i<total/step; i++)
		{
			List<User> users = UserService.getByPageAndCondition(i*step, step, 0, 0, null, null, null);
			for(User user: users)
			{
				String password = user.getPassword();
				if (password.length() == 0) password = "a";

				if (password.indexOf("$H$") != 0)
				{
					password = StringDigest.hash(user.getPassword());
					user.setPassword(password);
					UserService.updateUser(user);
					System.out.println(user.getName() + ": \t\t" + user.getPassword() + "\t\t" + password);
				}
				else
				{
					System.out.println(user.getName() + ": \t" + user.getPassword());
				}
			}
			System.out.println("Completed: " + i*step);
		}
	}
}
